package partner_admin_roles

import (
	"fmt"
	"gitee.com/theegg/go-brick/app/model/partner/partner_admin/partner_admin_menus"
	"gitee.com/theegg/go-brick/app/model/partner/partner_admin/partner_admin_permissions"
	"gitee.com/theegg/go-brick/app/model/partner/partner_admin/partner_admin_role_menus"
	"gitee.com/theegg/go-brick/app/model/partner/partner_admin/partner_admin_role_permissions"
	"gitee.com/theegg/go-brick/app/model/partner/partner_admin/partner_admin_role_users"
	"gitee.com/theegg/go-brick/app/service/app"
	"gitee.com/theegg/go-brick/app/service/help/cmap"
	"strconv"
	"time"
)

// 添加角色的参数
type AdminRoleAddParams struct {
	Ip     string
	UserId int64
	Name   string `form:"name" json:"name"  binding:"required,min=3,max=24" label:"角色名称"`
	Mark   string `form:"mark" json:"mark"  binding:"required,min=3,max=24" label:"角色备注"`
}

var SupperRoleId int64 = 1

// 分页获取所有数据
// @param params map 参数
// @param pageSize int 每页数据量
// @return mix
func (par PartnerAdminRoles) GetDataList(params map[string]string, pageSize int) (interface{}, error) {
	returnData := make(map[string]interface{})

	items := make([]PartnerAdminRoles, 0)

	offset := 0
	if _, ok := params["page_index"]; ok {
		intPageSize, err := strconv.Atoi(params["page_index"])
		if err != nil {
			return nil, err
		}

		offset = (intPageSize - 1) * pageSize
	}

	query := app.Db().Desc("id").Limit(pageSize, offset)

	// 当前的直接下级
	query.Where("pid = ?", par.Id)

	// 状态判断
	if _, ok := params["status"]; ok {
		query.And("status = ?", params["status"])
	}

	// 查询多条数据
	total, errQuery := query.FindAndCount(&items)
	if errQuery != nil {
		app.Log().Error("model-blogs-err-find-" + errQuery.Error())
		return nil, errQuery
	}

	returnData["total"] = total
	returnData["data"] = items

	return returnData, nil
}

// 添加角色
func (par PartnerAdminRoles) AddRole(params AdminRoleAddParams) (*PartnerAdminRoles, error) {
	arNew := new(PartnerAdminRoles)
	arNew.Name = params.Name
	arNew.Mark = params.Mark

	arNew.Pid = par.Id
	arNew.Rid = par.Rid + "|" + strconv.FormatInt(par.Id, 10)
	arNew.AddUserId = params.UserId
	arNew.AddUserIp = params.Ip
	arNew.CreatedAt = time.Now()

	affected, err := app.Db().Insert(arNew)

	if err != nil {
		return nil, err
	}

	if affected != 1 {
		return nil, fmt.Errorf("新增用户错误(0x001)")
	}

	return arNew, nil
}

// @title ModifyStatus
// @description 修改管理员状态
func (par *PartnerAdminRoles) EditRoleInfo(params AdminRoleAddParams) (bool, error) {

	affected, err := app.Db().Table(new(PartnerAdminRoles)).ID(par.Id).Cols("name", "mark").Update(map[string]string{"name": params.Name, "mark": params.Mark})

	if err != nil {
		return false, app.NewError(err)
	}

	// 生效条数
	if affected == 0 {
		return false, app.NewError("对不起, 更新未成功")
	}

	return true, nil
}

// @title ModifyStatus
// @description 修改管理员状态
func (par *PartnerAdminRoles) ModifyStatus() (bool, error) {
	status := 1
	if par.Status == 1 {
		status = 0
	}

	affected, err := app.Db().Table(new(PartnerAdminRoles)).ID(par.Id).Cols("status").Update(map[string]int{"status": status})

	if err != nil {
		return false, app.NewError(err)
	}

	// 生效条数
	if affected == 0 {
		return false, app.NewError("对不起, 指定的ID更新数量不正确")
	}

	return true, nil
}

// @title EditRoleMenus
// @description 编辑角色的菜单
func (par *PartnerAdminRoles) EditRoleMenus(targetRole *PartnerAdminRoles, menuIds map[int64]int64) (bool, error) {
	// 1. 获取当前角色 分配的　menus
	currentMenus, errCm := partner_admin_menus.GetItemByRoleIdFromCache(par.Id)
	if errCm != nil {
		return false, errCm
	}

	// 2. 检测ID
	loseParentIds := make(map[int64]int64, 0)
	for _, id := range menuIds {
		if _, ok := currentMenus[id]; !ok {
			return false, app.NewError("无效的menu Id")
		}

		// 上级ID要一并传递过来
		if currentMenus[id].Pid != 0 {
			if _, ok := menuIds[currentMenus[id].Pid]; !ok {
				loseParentIds[currentMenus[id].Pid] = currentMenus[id].Pid
			}
		}
	}

	// 3. 补进去
	if len(loseParentIds) > 0 {
		for _, id := range loseParentIds {
			menuIds[currentMenus[id].Pid] = currentMenus[id].Pid
		}
	}

	targetMenus, errTm := partner_admin_menus.GetItemByRoleIdFromCache(targetRole.Id)
	if errTm != nil {
		return false, errTm
	}

	// 3. 遍历出哪些是新增
	addMenuIds := make([]int64, 0)
	for _, id := range menuIds {
		if _, ok := targetMenus[id]; !ok {
			addMenuIds = append(addMenuIds, id)
		}
	}

	// 4. 遍历出哪些是移除
	removeMenuIds := make([]int64, 0)
	for tId, _ := range targetMenus {
		if ok := cmap.IsValueInt64ExistMapInt64(tId, menuIds); !ok {
			removeMenuIds = append(removeMenuIds, tId)
		}
	}

	/* ====================  开始事务  ==================== */
	session := app.Db().NewSession()
	defer session.Close()
	errSb := session.Begin()
	if errSb != nil {
		return false, app.NewError(errSb)
	}

	// 5-1. 目标角色增加菜单
	if len(addMenuIds) > 0 {
		roleMenus := make([]partner_admin_role_menus.PartnerAdminRoleMenus, 0)
		for _, aV := range addMenuIds {
			tmpStruct := partner_admin_role_menus.PartnerAdminRoleMenus{
				RoleId: targetRole.Id,
				MenuId: aV,
			}

			roleMenus = append(roleMenus, tmpStruct)
		}

		_, errInsert := session.Insert(&roleMenus)
		if errInsert != nil {
			session.Rollback()
			return false, errInsert
		}
	}

	// 5-2. 下级角色减少菜单
	// 获取当前角色所有的下级 直接 + 下下级
	childRoleIds, errChildRole := targetRole.GetChildRoleIds(false)
	if errChildRole != nil {
		return false, errChildRole
	}

	childRoleIds = append(childRoleIds, targetRole.Id)

	if len(removeMenuIds) > 0 {
		aprStruct := new(partner_admin_role_menus.PartnerAdminRoleMenus)
		_, errDelete := session.In("menu_id", removeMenuIds).In("role_id", childRoleIds).Delete(aprStruct)
		if errDelete != nil {
			session.Rollback()
			return false, errDelete
		}
	}

	// 刷新缓存
	for _, rId := range childRoleIds {
		_, errFlush := partner_admin_menus.DeleteCacheByRoleId(rId)
		if errFlush != nil {
			session.Rollback()
			return false, errFlush
		}
	}

	errCommit := session.Commit()
	if errCommit != nil {
		return false, errCommit
	}

	/* =============  结束事务 =========== */

	return true, nil
}

// @title EditRolePermissions
// @description 编辑角色的权限
func (par *PartnerAdminRoles) EditRolePermissions(targetRole *PartnerAdminRoles, permissionIds map[int64]int64) (bool, error) {
	// 1. 获取当前角色 分配的　权限
	currentPermissions, errCm := partner_admin_permissions.GetAdminPermissionsByRoleIdFromDb(par.Id, par.IsSuperRole())
	if errCm != nil {
		return false, errCm
	}

	// 2. 检测　ID　是否是当前登陆用户的角色已经分配
	for _, id := range permissionIds {
		if _, ok := currentPermissions[id]; !ok {
			return false, app.NewError("无效的 permission Id")
		}
	}

	targetPermissions, errTp := partner_admin_permissions.GetAdminPermissionsByRoleIdFromDb(targetRole.Id, targetRole.IsSuperRole())
	if errTp != nil {
		return false, errTp
	}

	// 3. 遍历出哪些是新增
	addPermissionIds := make([]int64, 0)
	for _, id := range permissionIds {
		if _, ok := targetPermissions[id]; !ok {
			addPermissionIds = append(addPermissionIds, id)
		}
	}

	// 4. 遍历出哪些是移除
	removePermissionIds := make([]int64, 0)
	for tId, _ := range targetPermissions {
		if ok := cmap.IsValueInt64ExistMapInt64(tId, permissionIds); !ok {
			removePermissionIds = append(removePermissionIds, tId)
		}
	}

	/* ====================  开始事务  ==================== */
	session := app.Db().NewSession()
	defer session.Close()
	errSb := session.Begin()
	if errSb != nil {
		return false, app.NewError(errSb)
	}

	// 5-1. 目标角色增加菜单
	if len(addPermissionIds) > 0 {
		rolePermissions := make([]partner_admin_role_permissions.PartnerAdminRolePermissions, 0)
		for _, aV := range addPermissionIds {
			tmpStruct := partner_admin_role_permissions.PartnerAdminRolePermissions{
				RoleId:       targetRole.Id,
				PermissionId: aV,
			}

			rolePermissions = append(rolePermissions, tmpStruct)
		}

		_, errInsert := session.Insert(&rolePermissions)
		if errInsert != nil {
			session.Rollback()
			return false, errInsert
		}
	}

	// 5-2. 下级角色减少菜单
	// 获取当前角色所有的下级 直接 + 下下级
	childRoleIds, errChildRole := targetRole.GetChildRoleIds(false)
	if errChildRole != nil {
		return false, errChildRole
	}

	childRoleIds = append(childRoleIds, targetRole.Id)

	if len(removePermissionIds) > 0 {
		aprStruct := new(partner_admin_role_permissions.PartnerAdminRolePermissions)
		_, errDelete := session.In("permission_id", removePermissionIds).In("role_id", childRoleIds).Delete(aprStruct)
		if errDelete != nil {
			session.Rollback()
			return false, errDelete
		}
	}

	// 刷新缓存
	for _, rId := range childRoleIds {
		_, errDelCache := partner_admin_permissions.DeleteCacheByRoleId(rId)
		if errDelCache != nil {
			session.Rollback()
			return false, errDelCache
		}
	}

	errCommit := session.Commit()
	if errCommit != nil {
		return false, errCommit
	}

	/* =============  结束事务 =========== */

	return true, nil
}

// 角色上绑定用户
func (par PartnerAdminRoles) BindUser(userId int64) (bool, error) {

	ok, err := partner_admin_role_users.BindUserToRole(par.Id, userId)
	if err != nil {
		return false, app.NewError(err)
	}

	if !ok {
		return false, app.NewError("对不去, 绑定用户到角色失败")
	}

	return true, nil
}

// @title GetItemById
// @description 获取item从数据库
func GetItemById(roleId int64) (*PartnerAdminRoles, error) {
	item := new(PartnerAdminRoles)

	has, err := app.Db().ID(roleId).Get(item)

	if err != nil {
		return nil, app.NewError(err)
	}

	if !has {
		return nil, app.NewError("对不起, 未查询到相关数据")
	}

	return item, nil
}

// 获取所有 可用 的角色
func (par PartnerAdminRoles) GetAllRoles() (map[int64]PartnerAdminRoles, error) {

	items := make(map[int64]PartnerAdminRoles, 0)

	err := app.Db().Where("status = ?", true).Find(&items)
	if err != nil {
		return nil, app.NewError(err)
	}

	return items, nil
}

// 通过pid 获取所有的角色
func (par PartnerAdminRoles) GetRolesByPid(pid int64) (map[int64]PartnerAdminRoles, error) {
	items := make(map[int64]PartnerAdminRoles, 0)

	err := app.Db().Where("pid = ?", pid).Find(&items)
	if err != nil {
		return nil, app.NewError(err)
	}

	return items, nil
}

// 获取 角色 所有的下级ID [id, id, id]
// @param bool 是否直接下级
func (par PartnerAdminRoles) GetChildRoleIds(onlyDirect bool) ([]int64, error) {
	items, err := par.GetChildRole(onlyDirect)
	if err != nil {
		return nil, app.NewError(err)
	}

	returnData := make([]int64, 0)
	for _, item := range items {
		returnData = append(returnData, item.Id)
	}

	return returnData, nil
}

// 获取所有的下级角色
func (par PartnerAdminRoles) GetChildRole(onlyDirect bool) (map[int64]PartnerAdminRoles, error) {
	items := make(map[int64]PartnerAdminRoles, 0)

	// 直接下级
	session := app.Db().Where("rid like ?", par.Rid+"|%")
	if onlyDirect {
		session.And("pid = ?", par.Id)
	}

	err := session.Find(&items)
	if err != nil {
		return nil, app.NewError(err)
	}

	return items, nil
}

// 获取 角色 所有的下级 === 前端使用
// @param bool 是否直接下级
func (par PartnerAdminRoles) GetChildRoleOption(onlyDirect bool) ([]map[string]string, error) {
	items, err := par.GetChildRole(onlyDirect)
	if err != nil {
		return nil, app.NewError(err)
	}

	returnData := make([]map[string]string, 0)

	for _, item := range items {
		tmp := map[string]string{"value": strconv.FormatInt(item.Id, 10), "label": item.Name}
		returnData = append(returnData, tmp)
	}

	return returnData, nil
}

// 检测是否拥有某个下级
func (par PartnerAdminRoles) HasChildRole(roleId int64) (bool, error) {
	item := new(PartnerAdminRoles)

	has, err := app.Db().Where("id = ?", roleId).Get(item)
	if err != nil {
		return false, app.NewError(err)
	}
	if !has {
		return false, nil
	}

	return par.Id == item.Pid, nil
}

// 是不是超级角色
func (par PartnerAdminRoles) IsSuperRole() bool {
	return par.Id == SupperRoleId
}

// 获取角色上分配的所有userIds
func (par PartnerAdminRoles) GetRoleBindUserIds() ([]int64, error) {
	ids, err := partner_admin_role_users.GetUserIdsByRoleId(par.Id)
	if err != nil {
		return nil, app.NewError(err)
	}

	return ids, nil
}

// 获取　多个角色　上　分配的所有　userIds
func GetMultiRoleBindUserIds(roleIds []int64) ([]int64, error) {
	ids, err := partner_admin_role_users.GetUserIdsByRoleIds(roleIds)
	if err != nil {
		return nil, app.NewError(err)
	}

	return ids, nil
}

/* ====================== 关联当前用户权限 ============================ */

// 关联当前用户权限
// @return map[int64]*partner_admin_permissions.PartnerAdminPermissions map类型
func (par *PartnerAdminRoles) Permissions() (map[int64]*partner_admin_permissions.PartnerAdminPermissions, error) {

	if par.Id == 0 {
		return nil, app.NewError("对不起，角色不存在(ar-P)")
	}

	// 获取用户的 permissions == 缓存

	permissions, errUserRole := partner_admin_permissions.GetAdminPermissionsByRoleIdFromDb(par.Id, par.IsSuperRole())
	// 如果没有查询到 直接返回
	if errUserRole != nil {
		return nil, app.NewError("m-a-u-P-0001-" + errUserRole.Error())
	}

	par.permissions = permissions

	return par.permissions, nil
}

/* ========================== 辅助操作 ============================ */

// @help
// @title 把当前角色的权限转成 map {k => v}
func (par PartnerAdminRoles) HelpPermissionToKV() (map[int64]string, error) {
	permissions, err := par.Permissions()
	if err != nil {
		return nil, app.NewError(err)
	}

	returnData := make(map[int64]string)
	for k, item := range permissions {
		returnData[k] = item.Name
	}

	return returnData, nil
}

// @help
// @title 把当前角色的权限转成 切片 [id, id, id]
func (par PartnerAdminRoles) HelpPermissionToKey() ([]int64, error) {
	permissions, err := par.Permissions()
	if err != nil {
		return nil, app.NewError(err)
	}

	returnData := make([]int64, 0)
	for k, _ := range permissions {
		returnData = append(returnData, k)
	}

	return returnData, nil
}

// @help
// @title 把当前角色的权限转成 map {k:k} [id:id, id:id, id:id]
func (par PartnerAdminRoles) HelpPermissionToKK() (map[int64]int64, error) {
	permissions, err := par.Permissions()
	if err != nil {
		return nil, app.NewError(err)
	}

	returnData := make(map[int64]int64)
	for k, _ := range permissions {
		returnData[k] = k
	}

	return returnData, nil
}
